package com.redlight.base;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.redlight.utils.StringUtil;

import java.lang.reflect.*;
import java.util.*;

/**
 * Created by chao on 2019/1/9.
 */
public class Reflections {
    private static final String SETTER_PREFIX = "set";
    private static final String GETTER_PREFIX = "get";
    private static final String CGLIB_CLASS_SEPARATOR = "$$";
    private static Logger LOGGER = LoggerFactory.getLogger(Reflections.class);

    public Reflections() {
    }

    public static Object invokeGetter(Object obj, String propertyName) {
        String getterMethodName = "get" + StringUtils.capitalize(propertyName);
        return invokeMethod(obj, getterMethodName, new Class[0], new Object[0]);
    }

    public static void invokeSetter(Object obj, String propertyName, Object value) {
        String setterMethodName = "set" + StringUtils.capitalize(propertyName);
        invokeMethodByName(obj, setterMethodName, new Object[]{value});
    }

    public static Object getFieldValue(Object obj, String fieldName) {
        if(null != obj && null != fieldName) {
            String[] fieldArr = fieldName.split("\\.");

            for(int i = 0; i < fieldArr.length; ++i) {
                String f = fieldArr[i];
                if(i == fieldArr.length - 1) {
                    fieldName = f;
                } else {
                    obj = getAccessibleField(obj, f).getType();
                }
            }

            Field field = getAccessibleField(obj, fieldName);
            if(field == null) {
                throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]");
            } else {
                Object result = null;

                try {
                    if(obj instanceof Class) {
                        obj = ((Class)obj).newInstance();
                    }

                    result = field.get(obj);
                } catch (Exception var6) {
                    LOGGER.error("不可能抛出的异常{}", var6.getMessage());
                }

                return result;
            }
        } else {
            return null;
        }
    }

    public static void setFieldValue(Object obj, String fieldName, Object value) {
        String[] fieldArr = fieldName.split("\\.");

        for(int i = 0; i < fieldArr.length; ++i) {
            String f = fieldArr[i];
            if(i == fieldArr.length - 1) {
                fieldName = f;
            } else {
                obj = getAccessibleField(obj, f).getType();
            }
        }

        Field field = getAccessibleField(obj, fieldName);
        if(field == null) {
            throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]");
        } else {
            try {
                if(obj instanceof Class) {
                    obj = ((Class)obj).newInstance();
                }

                field.set(obj, value);
            } catch (Exception var6) {
                LOGGER.error("不可能抛出的异常:{}", var6.getMessage());
            }

        }
    }

    public static Object invokeMethod(Object obj, String methodName, Class<?>[] parameterTypes, Object[] args) {
        Method method = getAccessibleMethod(obj, methodName, parameterTypes);
        if(method == null) {
            throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]");
        } else {
            try {
                return method.invoke(obj, args);
            } catch (Exception var6) {
                throw convertReflectionExceptionToUnchecked(var6);
            }
        }
    }

    public static Object invokeMethodByName(Object obj, String methodName, Object[] args) {
        Method method = getAccessibleMethodByName(obj, methodName);
        if(method == null) {
            throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]");
        } else {
            try {
                return method.invoke(obj, args);
            } catch (Exception var5) {
                throw convertReflectionExceptionToUnchecked(var5);
            }
        }
    }

    public static Field getAccessibleField(Object obj, String fieldName) {
        Validate.notNull(obj, "object can't be null", new Object[0]);
        Validate.notBlank(fieldName, "fieldName can't be blank", new Object[0]);
        Class superClass = obj instanceof Class?(Class)obj:obj.getClass();

        while(superClass != Object.class) {
            try {
                Field field = superClass.getDeclaredField(fieldName);
                makeAccessible(field);
                return field;
            } catch (NoSuchFieldException var4) {
                superClass = superClass.getSuperclass();
            }
        }

        return null;
    }

    public static Method getAccessibleMethod(Object obj, String methodName, Class... parameterTypes) {
        Validate.notNull(obj, "object can't be null", new Object[0]);
        Validate.notBlank(methodName, "methodName can't be blank", new Object[0]);
        Class searchType = obj.getClass();

        while(searchType != Object.class) {
            try {
                Method method = searchType.getDeclaredMethod(methodName, parameterTypes);
                makeAccessible(method);
                return method;
            } catch (NoSuchMethodException var5) {
                searchType = searchType.getSuperclass();
            }
        }

        return null;
    }

    public static Method getAccessibleMethodByName(Object obj, String methodName) {
        Validate.notNull(obj, "object can't be null", new Object[0]);
        Validate.notBlank(methodName, "methodName can't be blank", new Object[0]);

        for(Class searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) {
            Method[] methods = searchType.getDeclaredMethods();
            Method[] var4 = methods;
            int var5 = methods.length;

            for(int var6 = 0; var6 < var5; ++var6) {
                Method method = var4[var6];
                if(method.getName().equals(methodName)) {
                    makeAccessible(method);
                    return method;
                }
            }
        }

        return null;
    }

    public static void makeAccessible(Method method) {
        if((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers())) && !method.isAccessible()) {
            method.setAccessible(true);
        }

    }

    public static void makeAccessible(Field field) {
        if((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers()) || Modifier.isFinal(field.getModifiers())) && !field.isAccessible()) {
            field.setAccessible(true);
        }

    }

    public static <T> Class<T> getClassGenricType(Class clazz) {
        return getClassGenricType(clazz, 0);
    }

    public static Class getClassGenricType(Class clazz, int index) {
        Type genType = clazz.getGenericSuperclass();
        if(!(genType instanceof ParameterizedType)) {
            LOGGER.warn(clazz.getSimpleName() + "'s superclass not ParameterizedType");
            return Object.class;
        } else {
            Type[] params = ((ParameterizedType)genType).getActualTypeArguments();
            if(index < params.length && index >= 0) {
                if(!(params[index] instanceof Class)) {
                    LOGGER.warn(clazz.getSimpleName() + " not set the actual class on superclass generic parameter");
                    return Object.class;
                } else {
                    return (Class)params[index];
                }
            } else {
                LOGGER.warn("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: " + params.length);
                return Object.class;
            }
        }
    }

    public static Class<?> getUserClass(Object instance) {
        Validate.notNull(instance, "Instance must not be null", new Object[0]);
        Class clazz = instance.getClass();
        if(clazz != null && clazz.getName().contains("$$")) {
            Class<?> superClass = clazz.getSuperclass();
            if(superClass != null && !Object.class.equals(superClass)) {
                return superClass;
            }
        }

        return clazz;
    }

    public static Class getClassByFullName(String classFullName) {
        Class clazz = null;

        try {
            if(StringUtils.isNotBlank(classFullName)) {
                classFullName = classFullName.replaceAll("\\\\", "/");
                if(0 < classFullName.indexOf("/classes")) {
                    classFullName = classFullName.substring(classFullName.indexOf("/classes") + 9);
                }

                clazz = Class.forName(classFullName.replaceAll("/", "."));
            }
        } catch (Exception var3) {
            var3.printStackTrace();
        }

        return clazz;
    }

    public static RuntimeException convertReflectionExceptionToUnchecked(Exception e) {
        return (RuntimeException)(!(e instanceof IllegalAccessException) && !(e instanceof IllegalArgumentException) && !(e instanceof NoSuchMethodException)?(e instanceof InvocationTargetException?new RuntimeException(((InvocationTargetException)e).getTargetException()):(e instanceof RuntimeException?(RuntimeException)e:new RuntimeException("Unexpected Checked Exception.", e))):new IllegalArgumentException(e));
    }

    public static Map<String, Map<String, String>> compareBeanField(Object oldBean, Object newBean, String... compareFields) {
        Map<String, Map<String, String>> retMap = new HashMap();
        Object pojo1 = oldBean;
        Object pojo2 = newBean;

        try {
            List<String> validFieldList = new ArrayList();
            if(null != compareFields) {
                validFieldList = Arrays.asList(compareFields);
            }

            if(0 == ((List)validFieldList).size()) {
                return retMap;
            } else {
                Iterator var7 = ((List)validFieldList).iterator();

                while(true) {
                    String fieldName;
                    Object o1;
                    Object o2;
                    HashMap valueMap;
                    do {
                        if(!var7.hasNext()) {
                            return retMap;
                        }

                        fieldName = (String)var7.next();
                        o1 = getFieldValue(pojo1, fieldName);
                        if(o1 instanceof BaseEntity && o1 != null) {
                            o1 = getFieldValue(o1, "id");
                        }

                        if(null == o1) {
                            o1 = "";
                        }

                        o2 = getFieldValue(pojo2, fieldName);
                        if(o2 instanceof BaseEntity && o1 != null) {
                            o2 = getFieldValue(o2, "id");
                        }

                        if(null == o2) {
                            o2 = "";
                        }

                        valueMap = new HashMap();
                    } while(o1.toString().equals(o2.toString()));

                    valueMap.put("oldValue", o1.toString());
                    valueMap.put("newValue", o2.toString());
                    String label = "";
                    Object obj = pojo1;
                    String[] fieldArr = fieldName.split("\\.");

                    for(int i = 0; i < fieldArr.length; ++i) {
                        String f = fieldArr[i];
                        if(i == fieldArr.length - 1) {
                            fieldName = f;
                        } else {
                            obj = getAccessibleField(obj, f).getType();
                        }
                    }

                    Field field = getAccessibleField(obj, fieldName);
                    FieldLabel fl = (FieldLabel)field.getAnnotation(FieldLabel.class);
                    if(null != fl && StringUtil.isNotBlank(fl.value())) {
                        label = fl.value();
                    } else {
                        label = fieldName;
                    }

                    valueMap.put("label", label);
                    retMap.put(fieldName, valueMap);
                }
            }
        } catch (Exception var17) {
            var17.printStackTrace();
            return retMap;
        }
    }

    public static void main(String[] args) {
    }
}
